#include <QApplication>
#include <QDir>

#include "qtprojectgeneratorfactory.h"
#include "rcbuildtask.h"
#include "rcsession.h"
#include "fileutilities.h"

#include "defines.h"

#include "rcsymbiandefines.h"
#include "rcsymbianqtprojectgenerator.h"
#include "rcsymbiansettingsgui.h"

#include "common/networksettingsdialog.h"

#include "symbian/symbianstatusupdater.h"


RcSymbianQtProjectGenerator::RcSymbianQtProjectGenerator(const QString       & platformId,
                                                         GeneratorOutputView & outputView,
                                                         QObject             * parent)
    : SymbianQtProjectGenerator(outputView,
                                parent)
    , m_rcSession(NULL)
    , m_rcBuildTask(NULL)
{
    // the platform id is actually the wccParams plus a prefix
    m_wccParams = platformId.mid(QString(DYN_BUILDTARGET).length());

    // It does look strange to connect a signal to a slot on the same
    // object. However, the signal is emitted by the parent class
    // too, and there is an action we have to take regardless of
    // who (parent or this) class method is emitting the signal.
    connect(this,
            SIGNAL(finished(int)),
            this,
            SLOT(finishedSlot(int)));

    m_generatorData.setRemotelyCompiled(true);
}


RcSymbianQtProjectGenerator::~RcSymbianQtProjectGenerator()
{
    delete m_rcBuildTask;
    m_rcBuildTask = NULL;
}


IStatusUpdater * RcSymbianQtProjectGenerator::createStatusUpdater(QObject * parent)
{
    // TODO for now, we reuse the same status updater as SymbianQtProjectGenerator
    //      later, we should probably need our own one. Reason: different amount
    //      of log messages, different way of providing pkgFileInfo() about a successful
    //      build, etc.
    return new SymbianStatusUpdater(*this,
                                    parent);
}


void RcSymbianQtProjectGenerator::build(const QString & widgetFile,
                                        RcSession     & rcSession)
{
    QPair<QString, QString>
        appNames = FileUtilities::sniffAppNames(widgetFile);
    m_appName = appNames.first;

    m_rcSession = &rcSession;

    if (!m_rcSession->isSignedOn())
    {
        NetworkSettingsDialog
            nsDlg(m_rcSession,
                  NULL);
        nsDlg.exec();

        if (!nsDlg.justSignedIn())
        {
            registerStatus(false);
            m_outputView.printOutput("Connecting to remote compiler failed.");
            emit finished(EXIT_FAILURE);
            return;
        }
    }

    m_oldFullS60SDK = Settings::get(Settings::FullS60SDK).toBool();
    Settings::set(Settings::FullS60SDK,
                  true);

    SymbianQtProjectGenerator::build(widgetFile,
                                     rcSession);
}


void RcSymbianQtProjectGenerator::rebuild(RcSession     & rcSession)
{
    m_rcSession = &rcSession;

    // TODO factor out with the above code
    if (!m_rcSession->isSignedOn())
    {
        NetworkSettingsDialog
            nsDlg(m_rcSession,
                  NULL);
        nsDlg.exec();

        if (!nsDlg.justSignedIn())
        {
            registerStatus(false);
            m_outputView.printOutput("Connecting to remote compiler failed.");
            emit finished(EXIT_FAILURE);
            return;
        }
    }

    m_oldFullS60SDK = Settings::get(Settings::FullS60SDK).toBool();
    Settings::set(Settings::FullS60SDK,
                  true);

    SymbianQtProjectGenerator::rebuild(rcSession);
}


QString RcSymbianQtProjectGenerator::getStatusText() const
{
    QString statusText;

    switch(m_currentGeneratorPhase.m_phase)
    {
    case RCS_UNZIP_WIDGET:
        statusText = HAG_STATUS_EXTRACTING_WIDGET;
        break;
    case RCS_QMAKE_APP:
    case RCS_MAKE_APP:
    case RCS_MAKESIS_APP:
        statusText = "Starting remote build task";
        break;
    case RCS_PKGZIPPING:
        statusText = "Zipping package to upload";
        break;
    case RCS_PKGUPLOADING_WAITING:
        statusText = "Uploading & waiting for remote build";
        break;
    case RCS_DOWNLOADING:
        statusText = "Downloading built package";
        break;

    case RCS_INITIAL:
        statusText = HAG_STATUS_IDLE;
        break;
    case RCS_ENDED_SUCCESSFULLY:
        statusText = HAG_STATUS_COMPLETED_OK;
        break;
    case RCS_ENDED_WITH_ERRORS:
        statusText = HAG_STATUS_COMPLETED_NOTOK;
        break;
    }

    return statusText;
}


QWidget * RcSymbianQtProjectGenerator::createSettingsWidget(const QString & /* widgetFile */,
                                                            QWidget       * parent) const
{
    QWidget
        * rv = new RcSymbianSettingsGui(parent);

    return rv;
}


void RcSymbianQtProjectGenerator::saveSettings(QWidget * settingsWidget) const
{
    RcSymbianSettingsGui
        * rcSymbianSettingsGui = dynamic_cast<RcSymbianSettingsGui*>(settingsWidget);

    if (rcSymbianSettingsGui != NULL)
    {
        rcSymbianSettingsGui->saveSettings();
    }
}

QStringList RcSymbianQtProjectGenerator::errorsForTarget(GeneratorTarget generatorTarget) const
{
    QStringList
        rv;

    QString
        forumNokiaUserName = Settings::get(Settings::ForumNokiaUserName).toString();
    int
        proxyConfig = Settings::get(Settings::ProxyConfig).toInt();

    if (forumNokiaUserName.length() == 0
        || proxyConfig == Settings::PCK_UndefinedProxyConfig)
    {
        rv.append("Network settings undefined");
    }

    // Try to open the log file for writing
    QFile log(Settings::get(Settings::LogFilePath).toString());
    if (!log.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        // Failed to open the log file
        if (generatorTarget != NO_TARGET)
        {
            rv.append("Failed to open log file for writing! Check settings.");
        }
    }
    log.close();

    return rv;
}


void RcSymbianQtProjectGenerator::startBuild()
{
    m_currentGeneratorPhase = RCS_QMAKE_APP;
    m_rcBuildTask = new RcBuildTask(this->m_outputView,
                                    *this->m_rcSession,
                                    this->m_appName,
                                    this->m_generatorData.projectDirectory(),
                                    this);
    connect(m_rcBuildTask,
            SIGNAL(buildCompleted(bool,QString)),
            this,
            SLOT(buildCompletedSlot(bool,QString)));
    connect(m_rcBuildTask,
            SIGNAL(zipping()),
            this,
            SLOT(zippingSlot()));
    connect(m_rcBuildTask,
            SIGNAL(uploadingAndWaiting()),
            this,
            SLOT(uploadingAndWaitingSlot()));
    connect(m_rcBuildTask,
            SIGNAL(downloading()),
            this,
            SLOT(downloadingSlot()));

    QDir
        dloadDir = this->m_generatorData.projectDirectory();
    dloadDir.cdUp();

    m_rcBuildTask->startBuilding(m_wccParams,
                                 dloadDir.absolutePath());
}


void RcSymbianQtProjectGenerator::zippingSlot()
{
    m_currentGeneratorPhase = RCS_PKGZIPPING;
}


void RcSymbianQtProjectGenerator::uploadingAndWaitingSlot()
{
    m_currentGeneratorPhase = RCS_PKGUPLOADING_WAITING;
}


void RcSymbianQtProjectGenerator::downloadingSlot()
{
    m_currentGeneratorPhase = RCS_DOWNLOADING;
}


void RcSymbianQtProjectGenerator::buildCompletedSlot(bool    success,
                                                     QString downloadedFile)
{
    delete m_rcBuildTask;
    m_rcBuildTask = NULL;

    if (success)
    {
        m_currentGeneratorPhase = RCS_ENDED_SUCCESSFULLY;
        m_outputView.printOutput(QString("Remote build succeeded, "
                                         "file downloaded to %1").arg(downloadedFile));
        emit finished(EXIT_SUCCESS);
    }
    else
    {
        m_currentGeneratorPhase = RCS_ENDED_WITH_ERRORS;
        registerStatus(false);
        m_outputView.printOutput("Remote build failed.");
        emit finished(EXIT_FAILURE);
    }
}


void RcSymbianQtProjectGenerator::finishedSlot(int exitCode)
{
    Settings::set(Settings::FullS60SDK,
                  m_oldFullS60SDK);
}
